﻿using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;

namespace movie_tool_update
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private async void Window_Loaded(object sender, RoutedEventArgs e)
        {
            try
            {
                await WaitMovieToolExit();
                CopyUpdateFileToTarget();
                CleanUpdatePath();
                RunMovieToolProcess();
            }
            catch(Exception ex)
            {
                MessageBox.Show("程序升级失败：" + ex.Message, "升级");
            }
        }

        private async Task WaitMovieToolExit()
        {
            Task task = new Task(()=> {
                Process[] processes = Process.GetProcessesByName("盎宇宙全息剧本配置工具");
                while (processes != null && processes.Length > 0)
                {
                    File.WriteAllText("logs/update.log", "检测到" + processes.Length + "个程序在运行");
                    Thread.Sleep(1000);
                    processes = Process.GetProcessesByName("盎宇宙全息剧本配置工具");
                }
            });
            task.Start();
            await task;
        }

        public void CopyUpdateFileToTarget()
        {
            string path = UpdateTempPath();
            string target = AssembleRootPath();
            if (!Directory.Exists(path))
            {
                return;
            }
            string[] files = Directory.GetFiles(path, "*", SearchOption.AllDirectories);
            foreach (string item in files)
            {
                string relativePath = Path.GetRelativePath(path, item);
                if (relativePath.Contains("movie-tool-update"))
                {
                    continue;
                }
                string filePath = Path.Combine(target, relativePath);
                string sha1 = FileDigest(filePath);
                string sha2 = FileDigest(item);
                if (!object.Equals(sha1, sha2))
                {
                    DirectoryInfo info = Directory.GetParent(filePath);
                    if(info == null)
                    {
                        continue;
                    }
                    if (!info.Exists)
                    {
                        Directory.CreateDirectory(info.FullName);
                    }
                    File.Copy(item, filePath, true);
                }
            }
        }
        private void CleanUpdatePath()
        {
            string path = UpdateTempPath();
            CleanPath(path);
        }

        private void CleanPath(string path)
        {
            if (!Directory.Exists(path))
            {
                return;
            }
            foreach (string item in Directory.EnumerateFileSystemEntries(path))
            {
                DirectoryInfo info = new DirectoryInfo(item);
                if (Directory.Exists(item))
                {
                    CleanPath(item);
                }else if (File.Exists(item))
                {
                    File.Delete(item);
                }
            }
            Directory.Delete(path);
        }
        public static string FileDigest(string filePath)
        {
            if (File.Exists(filePath))
            {
                try
                {
                    using (FileStream fileStream = File.Open(filePath, FileMode.Open))
                    {
                        using (SHA1 sha1 = SHA1.Create())
                        {
                            byte[] bytes = sha1.ComputeHash(fileStream);
                            StringBuilder sb = new StringBuilder();
                            return string.Join(null, bytes.Select(item => string.Format("{0:x2}", item)));
                        }
                    }
                }
                catch (Exception e)
                {
                    return string.Empty;
                }

            }
            return string.Empty;
        }
        /// <summary>
        /// 执行更新程序,将
        /// </summary>
        public void RunMovieToolProcess()
        {
            string file = Path.Combine(AssembleRootPath(), "盎宇宙全息剧本配置工具.exe");
            if (File.Exists(file))
            {
                ProcessStartInfo info = new ProcessStartInfo(file);
                Process process = new Process();
                process.StartInfo = info;
                process.Start();
                Process.GetCurrentProcess().CloseMainWindow();
            }
            else
            {
                MessageBox.Show("盎宇宙全息剧本配置工具运行程序不存在");
            }
        }

        private string UpdateTempPath()
        {
            string path = AssembleRootPath();
            DirectoryInfo di = Directory.GetParent(path);
            path = di == null ? "" : di.FullName;
            if (string.IsNullOrWhiteSpace(path))
            {
                return string.Empty;
            }
            return Path.Combine(path, "update");
        }

        private string AssembleRootPath()
        {
            string path = GetAssembly().Location;
            DirectoryInfo di = Directory.GetParent(path);
            return di == null ? "" : di.FullName;
        }

        /// <summary>
        /// 获取定义对象的程序集或者调用此函数的函数所在的程序集
        /// </summary>
        /// <param name="o">程序集中定义的对象</param>
        /// <returns>如果o不为null,则返回声明o的类型的程序集，如果o为范型，则返回定义o的程序集
        /// <para>如果o为null，则返回调用此函数的函数所在的程序集</para></returns>
        public static Assembly GetAssembly(object o)
        {
            if (o != null)
            {
                return o.GetType().Assembly;
            }
            return Assembly.GetCallingAssembly();
        }

        public static Assembly GetAssembly()
        {
            return GetAssembly(null);
        }
    }
}
